package cars

import (
	"context"
	"errors"
	"fmt"
	"parking-lot-go-push/config"
	"parking-lot-go-push/controller/static_parking"
	"parking-lot-go-push/model"
	"parking-lot-go-push/model/order"
	"parking-lot-go-push/mongodb"
	"time"

	"go.mongodb.org/mongo-driver/bson"
)

type CarsOutStruct struct {
	Id             int       `gorm:"type:int(11) auto_increment; NOT NULL; primary_key"`
	ParkCode       string    `gorm:"type:varchar(255); COMMENT:'停车场码'"`
	ParkName       string    `gorm:"type:varchar(255); COMMENT:'停车场名称'"`
	CarNumber      string    `gorm:"type:varchar(255); COMMENT:'车牌号'"`
	InTime         time.Time `gorm:"type:datetime; COMMENT:'入场时间'"`
	InPhoto        string    `gorm:"type:varchar(255); COMMENT:'入场图片'"`
	OutTime        time.Time `gorm:"type:datetime; COMMENT:'出场时间'"`
	OutPhoto       string    `gorm:"type:varchar(255); COMMENT:'出场图片'"`
	RegionCode     string    `gorm:"type:varchar(255); COMMENT:'出场区域编号'"`
	RegionName     string    `gorm:"type:varchar(255); COMMENT:'出场区域名称'"`
	ParkTime       int       `gorm:"type:int(11); COMMENT:'停车时长,单位：分钟'"`
	ParkAmt        int       `gorm:"type:int(11); COMMENT:'停车费用，单位：分'"`
	CouponAmt      int       `gorm:"type:int(11); COMMENT:'停车优惠，单位：分'"`
	ChargeAmt      int       `gorm:"type:int(11); COMMENT:'实收金额，单位：分'"`
	SerialNo       string    `gorm:"type:varchar(255); COMMENT:'出场流水号'"`
	Otype          int       `gorm:"type:int(11); COMMENT:'结算方式（企业1，个人2，混合3）'"`
	AmountPlatform int       `gorm:"type:int(11); COMMENT:'平台扣款，单位：分'"`
	AmountUser     int       `gorm:"type:int(11); COMMENT:'个人结算金额，单位：分'"`
	CreatedAt      time.Time `gorm:"type:datetime"`
	UpdatedAt      time.Time `gorm:"type:datetime"`
	CarNoColor     int       `gorm:"type:tinyint(1); COMMENT:'车牌颜色'"`
	MuchId         string    `gorm:"type:varchar(255)"`
	OrderNo        string    `gorm:"type:varchar(255)"`
	OrderType      int       `gorm:"type:tinyint(1); COMMENT:'订单类型'"`
	CarType        int       `gorm:"type:tinyint(1); COMMENT:'车辆类型'"`
	PushStatus     int       `gorm:"type:tinyint(1); COMMENT:'推送状态'"`
	PushErrNum     int       `gorm:"type:tinyint(1); COMMENT:'失败次数'"`
	PushTime       int       `gorm:"type:tinyint(1); COMMENT:'下次推送时间'"`
}

func (c *CarsOutStruct) TableName() string {
	return "cars_out"
}

// 推送成功
func (c *CarsOutStruct) PushSuccess(orderNo, outTime string, orderType int, unBindCarData map[string]interface{}) error {
	// 开始事务
	tx := model.Db.Begin()

	//更新推送状态
	tx.Model(&CarsOutStruct{}).Where("order_no", orderNo).Update("push_status", 1)

	//更新订单表
	tx.Model(&order.OrderStruct{}).Where("order_no", orderNo).Updates(map[string]interface{}{
		"status":   2,
		"out_time": outTime,
	})

	//判断表类型
	var updateStruct interface{}
	switch orderType {
	case 0: //如之停车 (不需要额外更新)
		updateStruct = nil
	case 1: //小强
		updateStruct = &order.OrderXiaoqiangStruct{}
	case 2: //泊安飞
		updateStruct = &order.OrderParknflyStruct{}
	case 3: //钉钉 (不需要额外更新)
		updateStruct = nil
	default:
		// 未知类型的处理
		tx.Rollback()
		return errors.New("三方表类型不存在")
	}

	if updateStruct != nil {
		//更新三方表
		tx.Model(updateStruct).Where("order_no", orderNo).Updates(map[string]interface{}{
			"status": 2,
		})
	}

	if tx.Error != nil {
		// 发生错误，回滚事务
		tx.Rollback()

		return tx.Error
	}

	//删除mongdb记录
	ctx := context.TODO()
	var carsOutMongoDb mongodb.CarsOutMongoDbStruct
	model.MongoDb.Collection(carsOutMongoDb.MongoDBTableName()).DeleteMany(ctx, bson.M{"order_no": orderNo})

	//白名单查询
	var carsWhiteList CarsWhiteListStruct
	exists, _ := model.GetModelDataFirst(
		model.Db,
		carsWhiteList.TableName(),
		&carsWhiteList,
		model.QueryOptions{
			Conditions: map[string]interface{}{
				"car_number": unBindCarData["carId"],
			},
		})

	//白名单不解绑
	seeting := getSetting()
	if seeting && exists == false {
		//通知静态解除白名单
		staticSigner := static_parking.NewSigner()
		staticSignature := staticSigner.Sign(unBindCarData)
		if err, _ := staticSigner.CurlPostJson("openapi/hd/nobindCar", staticSignature, unBindCarData); err != nil {
			tx.Rollback()
			return errors.New(fmt.Sprintf("同步静态消息失败:%s", err.Error()))
		}
	}

	tx.Commit()

	// 检查提交是否出现错误
	if tx.Error != nil {
		return tx.Error
	}
	return nil
}

// 推送失败更新状态
func (c *CarsOutStruct) PushError(orderNo string, errNum int) error {

	ctx := context.TODO()
	var err error

	//重试时间计算
	lastPushTime := int(time.Now().Unix())
	switch errNum {
	case 3:
		lastPushTime += 3 * 60
	case 4:
		lastPushTime += 5 * 60
	default:
		lastPushTime += 60
	}

	var carsOutMongoDb mongodb.CarsOutMongoDbStruct

	//更新mongdb数据
	_, err = model.MongoDb.
		Collection(carsOutMongoDb.MongoDBTableName()).
		UpdateOne(
			ctx,
			bson.M{"order_no": orderNo},
			bson.M{
				"$set": bson.M{
					"push_err_num": errNum + 1,
					"push_time":    lastPushTime,
				},
			})

	if err != nil {
		return errors.New("更新mongodb失败" + err.Error())
	}

	//更新mysql数据
	err = model.UpdateModelData(
		model.Db,
		c.TableName(),
		map[string]interface{}{
			"order_no": orderNo,
		},
		map[string]interface{}{
			"push_err_num": errNum + 1,
			"push_time":    lastPushTime,
		},
	)

	if err != nil {
		return errors.New("更新mysql失败" + err.Error())
	}

	return nil
}

// 获取当前环境
func getSetting() bool {

	// 读取配置文件
	dbSection := config.Cfg.Section("SYSTEM")
	setting := dbSection.Key("SETTING").String()
	if setting == "develop" {
		return false
	}
	return true
}
